// 属性名 战时效果 战后效果 全部数值的计算均向下取整
const statTips = [
    ["体质", "+0.2气血上限的防御,战后恢复0.1上限的生命"],
    ["智力", "+技能效果加成,+0.2命中,战后+0.3经验加成,战后恢复0.1上限的魔法"],
    ["攻击", "范围波动±0.2"],
    ["防御", "1抵消敌方正常攻击,0.9抵消敌方暴击攻击,每次抵消防御衰减0.15"],
    ["命中", "未命中+0.15命中"],
    ["运气", "+1.2暴击伤害,+0.2命中,0.5抵消敌方命中暴击率,1抵消暴击伤害"],
    ["速度", "决定先手权,+0.2攻击,+0.1命中,攻击频率最低0.5最高2"],
    ["暴击", "+0.5暴击伤害,触发暴击后暴击-0.15否则+0.1。暴击,攻击范围波动为1.5~2并附加暴击伤害"]
]
// 每个战斗结束回合处理一次 里面元素的格式为 {tag:'h',target:'m',...heroBuff}
let battleQueue = [];
let heroBuff = [
    // {
    //     // id 0 第0个 buff
    //     // type 0 正面buff
    //     // turn 0 有效的回合
    //     id: 0,
    //     type: 0,
    //     turn: 0,
    // },
]
let petBuff = [];
let monsterBuff = [];
const battleHandler = (mid) => {
    console.log("遭遇怪物", mid);
    if (!mid) {
        console.log("参数错误");
        return
    }
    if (mid >= 43 || mid < 0) {
        console.log("没有此编号的怪物");
        return
    }
    // 造成伤害的次回合间隔时间
    const turnTime = 1000;
    // 初始化人物属性
    let heroStat = JSON.parse(JSON.stringify(game.hero.heroInfo.abilities));
    // 只有英雄享受属性带来的战时加成
    heroStat[3] += Math.round(heroStat[0] * 0.2)
    heroStat[2] += Math.round(heroStat[6] * 0.2)
    heroStat[4] += Math.round(heroStat[1] * 0.2) + Math.round(heroStat[6] * 0.1) + Math.round(heroStat[5] * 0.2)
    heroStat[0] = game.hero.heroInfo.hp;
    heroStat[1] = game.hero.heroInfo.mp;
    // 必须先禁止玩家切换上阵宠物
    // 初始所有已上阵宠物的属性 深拷贝
    let heroPetStat = game.hero.petInfo.battlePet.map(e => e.stat);
    console.log(heroPetStat);
    // 初始化怪物属性
    let monsterStat = JSON.parse(JSON.stringify(monsterData[mid].a));
    // 有些事件会附加战前buff，这里处理
    handleEventQueue(mid);
    // 只运行一次渲染基本场景
    const renderBattleScreen = () => {
        const bts = document.querySelector(".battleScreen")
        bts.style.display = "block";
        const _left = bts.firstElementChild;
        const _right = bts.lastElementChild;
        renderHero = () => {
            let item = document.createElement('div');
            let hero = document.createElement('div');
            addClass(hero, 'battleHero');
            hero.style.backgroundImage = `url(icon/character/${heroesNames[game.hero.type]}.png)`;
            item.append(hero)
            // 战前buff
            for (let i = 0; i < heroBuff.length; i++) {
                const el = heroBuff[i];
                let buff = document.createElement('div');
                // 用 CSS 把 buff 设置成 hero 宽高的 1/4 
                let dirname = el.type == 0 ? 'buff' : 'debuff';
                let buffnames = el.type == 0 ? buffNames : debuffNames;
                buff.style.backgroundImage = `url(icon/${dirname}/${buffnames[el.id]}.png)`;
                buff.innerText = el.turn;
                item.append(buff)
            }
            return item;
        }
        renderPet = (j, pid) => {
            let item = document.createElement('div');
            let p = document.createElement('div');
            addClass(p, `battleHeroPet`);
            p.id = j;
            p.style.backgroundImage = `url(icon/monster/${monsterNames[pid]}.png)`;
            let area = document.createElement('div');
            addClass(area, 'petArea');
            item.append(p)
            item.append(area);
            for (let i = 0; i < (typeof petBuff[j] == 'object' ? petBuff[j].length : 0); i++) {
                const el = petBuff[j][i];
                let buff = document.createElement('div');
                let dirname = el.type == 0 ? 'buff' : 'debuff';
                let buffnames = el.type == 0 ? buffNames : debuffNames;
                buff.style.backgroundImage = `url(icon/${dirname}/${buffnames[el.id]}.png)`;
                buff.innerText = el.turn;
                item.append(buff)
            }
            return item;
        }
        renderMonster = () => {
            let item = document.createElement('div');
            let m = document.createElement('div');
            addClass(m, 'battleMonster');
            m.style.backgroundImage = `url(icon/monster/${monsterNames[mid]}.png)`;
            let area = document.createElement('div');
            addClass(area, 'monsterArea');
            item.append(m);
            item.append(area);
            for (let i = 0; i < monsterBuff.length; i++) {
                const el = monsterBuff[i];
                let buff = document.createElement('div');
                let dirname = el.type == 0 ? 'buff' : 'debuff';
                let buffnames = el.type == 0 ? buffNames : debuffNames;
                buff.style.backgroundImage = `url(icon/${dirname}/${buffnames[el.id]}.png)`;
                buff.innerText = el.turn;
                item.append(buff)
            }
            return item;
        }
        _left.append(renderHero());
        for (let i = 0; i < heroPetStat.length; i++) {
            _left.append(renderPet(i, game.hero.petInfo.battlePet[i].mid))
        }
        _right.append(renderMonster());
    }
    // 渲染buff 参数1 'h' 参数2 该buff在 heroBuff 中的索引
    // 每次处理完一个单位的battlequeue后立即调用，更新buff状态
    const renderBuff = (person, buff) => {
        let box = null;
        switch (person) {
            case 'h':
                box = '.battleHero';
                break;
            case 'm':
                box = '.battleMonster';
                break;
            default:
                // .t1[id="1"] 类选择器 属性选择器
                box = `.battleHeroPet[id="${person}"]`;
                break;
        }
        box = document.querySelector(box)
        if (box) {
            box = box.parentElement;
            for (let i = 0; i < buff.length; i++) {
                let _buff = box.querySelector(`.buff[id="${el.id}"]`);
                if (buff.turn == 0) {
                    // 移除buff图标
                    box.removeChild(_buff);
                } else {
                    // 渲染buff图标
                    const el = buff[i];
                    if (!_buff) {
                        // 没有buff，新增buff
                        _buff = document.createElement('div');
                        _buff.id = el.id;
                        addClass(_buff, `buff`);
                        let dirname = el.type == 0 ? 'buff' : 'debuff';
                        let buffnames = el.type == 0 ? buffNames : debuffNames;
                        _buff.style.backgroundImage = `url(icon/${dirname}/${buffnames[el.id]}.png)`;
                        box.appendChild(_buff)
                    }
                    // 已有buff，更新持续时间，做简单点，单个buff的效果不再叠加，仅更新持续时间
                    _buff.innerText = el.turn
                }
            }
        }
    }
    renderBattleScreen();
    // 处理单只宠物技能
    const handlePetMove = (pid, tag, target) => {
        if (typeof monsterData[pid].func == 'function') {
            monsterData[pid].func(heroPetStat[tag], tag, target)
        }
    }
    // 处理战前生效一次的物品
    const initHeroItem = () => {
        game.hero.itemId.forEach((v) => {
            if (typeof (itemData[v].a) == 'object') {
                for (let i = 0; i < itemData[v].a.length; i++) {
                    heroStat[i] += itemData[v].a[i];
                }
            }
            if (typeof (itemData[v].buff) == 'function') {
                itemData[v].buff()
            }
        })
    }
    // 战前生效的物品
    initHeroItem();
    // 处理战中持续生效的物品
    const handleBattleHeroItem = () => {
        game.hero.itemId.forEach((v, i) => {
            if (typeof (v.func) == 'function') {
                itemData[game.hero.itemId[i]].func(heroStat)
            }
        })
    }
    const handleAllMove = (tag, target) => {
        // 简化成每次造成伤害前触发技能
        switch (tag) {
            case 'h':
                for (let i = 0; i < game.hero.heroInfo.activeMoveFlag.length; i++) {
                    // 遍历已拥有的技能
                    if (game.hero.heroInfo.activeMoveFlag[i] && heroStat[1] > 3) {
                        // 触发已激活的技能
                        let moveid = game.hero.heroInfo.hasMove[i];
                        if (typeof movesData[moveid].func == 'function') {
                            movesData[moveid].func(heroStat, tag, target);
                            // 统一消耗1~3点蓝
                            heroStat[1] -= getRandomRange(1, 3);
                        }
                    }
                }
                break;
            case 'm':
                if (typeof monsterData[mid].func == 'function') {
                    monsterData[mid].func(monsterStat, tag, target);
                }
                break;
            default:
                for (let i = 0; i < heroPetStat.length; i++) {
                    const pid = game.hero.petInfo.battlePet[i].mid;
                    if (typeof monsterData[pid].func == 'function') {
                        handlePetMove(pid, tag, target);
                    }
                }
                break;
        }
    }
    // 处理战前加成效果
    const initBuffArray = () => {
        heroBuff = [];
        for (let i = 0; i < heroPetStat.length; i++) {
            petBuff[i] = [];
        }
        monsterBuff = [];
    }
    initBuffArray();
    // 更新血条蓝条视图
    const updateHeroStat = () => {
        let oldValue = null;
        for (let i = 2; i < 8; i++) {
            oldValue = heroStat[i]
            if (panel.hero[i].innerText != oldValue) {
                panel.hero[i].innerText = oldValue
            }
        }
        oldValue = `${heroStat[0]}/${game.hero.heroInfo.abilities[0]}`;
        if (gameInfoBar[0].innerText != oldValue) {
            gameInfoBar[0].innerText = oldValue
            document.documentElement.style.setProperty('--hp', `${Math.round(heroStat[0] / game.hero.heroInfo.abilities[0] * 100)}%`);
        }
        oldValue = `${heroStat[1]}/${game.hero.heroInfo.abilities[1]}`
        if (gameInfoBar[1].innerText != oldValue) {
            gameInfoBar[1].innerText = oldValue;
            document.documentElement.style.setProperty('--mp', `${Math.round(heroStat[1] / game.hero.heroInfo.abilities[1] * 100)}%`)
        }
    }
    const updateHeroPetStat = (i) => {
        let oldValue = heroPetStat[i][0];
        let pet = document.querySelectorAll('.petArea')[i]
        if (oldValue <= 0) {
            pet.innerText = ''
        } else if (pet && pet.innerText != oldValue) {
            pet.innerText = oldValue;
        }
    }
    const updateMonsterStat = () => {
        let oldValue = monsterStat[0];
        let monster = document.querySelector('.monsterArea')
        if (oldValue <= 0) {
            monster.innerText = ''
        } else if (monster.innerText != oldValue) {
            monster.innerText = oldValue;
        }
    }
    updateHeroStat();
    const ifMiss = (s1, s2) => {
        let _d = (s1[4] - s2[5] * 0.5) * 2;
        console.log("命中率", _d);
        return _d > 100 ? true : (_d > getRandomRange(1, 100))
    }
    const ifCrit = (s1, s2) => {
        let _d = (s1[7] - s2[5] * 0.5) * 2;
        console.log("暴击率", _d);
        return _d > 100 ? true : (_d > getRandomRange(1, 100))
    }
    const critDamage = (s1, s2) => {
        let _d = Math.round(s1[2] * getRandomRange(15, 20) / 10 + s1[5] * 1.2 + s1[7] / 2 - s2[3] * 0.9 - s2[5])
        console.log("暴击伤害", _d);
        return _d > 0 ? _d : 2;
    }
    const normalDamage = (s1, s2) => {
        let _d = (Math.round(s1[2] * getRandomRange(8, 12) / 10) - s2[3])
        console.log("正常伤害", _d);
        return _d > 0 ? _d : 1;
    }
    const dealDamage = (_atk, _def, tag, target) => {
        // 命中判断
        if (ifMiss(_atk, _def)) {
            // 飘血
            let _d = 0;
            // 暴击判断
            if (ifCrit(_atk, _def)) {
                _d = critDamage(_atk, _def);
                // 暴击伤害结算
                _def[0] -= _d
                // 暴击衰减
                _atk[7] = Math.round(_atk[7] * 0.85)
                anim(tag, 'crit');
                console.log("触发暴击");
                anim(target, 'shake', _d);
            } else {
                _d = normalDamage(_atk, _def);
                // 正常伤害结算
                _def[0] -= _d
                // 暴击补正
                _atk[7] = Math.round(_atk[7] * 1.1)
                anim(tag, 'attack');
                console.log("正常攻击");
                anim(target, 'shake', _d);
            }
            // 防御衰减
            _atk[3] = Math.round(_atk[3] * 0.85)
            console.log("伤害数值", _d);
        } else {
            anim(tag, 'attack');
            console.log("攻击落空");
            anim(target, 'away');
            // miss 动画
            // 被攻击方幸运衰减
            if (_def[5] > Math.round(_atk[4] * 0.15)) {
                _def[5] -= Math.round(_atk[4] * 0.15)
            }
            // 命中补正
            _atk[4] = Math.round(_atk[4] * 1.15)
        }
    }
    let battleTurn = 0;
    const loadBuff = (tag, target) => {
        console.log("装载buff");
        let _targetBuff = null;
        switch (tag) {
            case 'h':
                _targetBuff = heroBuff;
                break;
            case 'm':
                _targetBuff = monsterBuff;
                break
            default:
                _targetBuff = petBuff[tag];
                break;
        }
        // 删掉所有 turn 为 0 的buff
        _targetBuff = _targetBuff.filter(e => e.turn > 0);
        let _tmp = null;
        for (let i = 0; i < _targetBuff.length; i++) {
            _tmp = JSON.parse(JSON.stringify({ ..._targetBuff[i], tag, target }));
            battleQueue.push(..._tmp);
        }
        _targetBuff.forEach(e => {
            e.turn--;
        });
    }
    const handleBattleQueue = (tag, target) => {
        console.log("处理战斗中buff");
        // 其他地方负责添加删除buff，这里负责只调用buff之类的活
        let _stat = null;
        let _buff = null;
        switch (tag) {
            case 'h':
                // 浅拷贝
                _stat = heroStat;
                _buff = heroBuff;
                break;
            case 'm':
                _stat = monsterStat;
                _buff = monsterBuff
                break;
            default:
                _stat = heroPetStat[tag];
                _buff = petBuff[tag]
                break;
        }
        // 更新视图
        renderBuff(tag, _buff)
        for (let i = 0; i < battleQueue.length; i++) {
            if (typeof battleQueue[i].func == 'function') {
                battleQueue[i].func(_stat, tag, target);
            }
        }
        // 队列持续1回合的buff结算完毕，舍去
        battleQueue = battleQueue.map(e => e.turn > 1);
        // 队列所有buff回合数减1
        battleQueue.forEach(e => e.turn--);
    }
    // 请求对战结果
    const battleResult = () => {
        // 根据速度决定攻击队列 h m ...pid
        // 速度慢的先push进来
        let attackQueue = [];
        const addQueue = () => {
            battleTurn++;
            // tag:发起攻击者 s:发起者属性 t:攻击目标
            let speeds = JSON.parse(JSON.stringify([{ tag: 'h', s: heroStat, t: 'm' }, { tag: 'm', s: monsterStat, t: 'h' }]));
            for (let i = 0; i < heroPetStat.length; i++) {
                speeds.push({ tag: i, s: heroPetStat[i], t: 'm' });
                // 宠物在一轮攻击栈中有40%几率吸引boss的攻击
                if (getRandomRange(1, 10) < 5) {
                    speeds[1].t = i;
                }
            }
            const cmp = function (v1, v2) {
                // 按照速度进行排序
                if (v1.s[6] > v2.s[6]) {
                    return 1;
                } else if (v1.s[6] < v2.s[6]) {
                    return -1;
                } else {
                    return 0;
                }
            }
            speeds = speeds.sort(cmp);
            console.log(`第${battleTurn}主回合`);
            let loop = speeds.length
            // 速度快的单位有概率多攻击一次
            for (let i = loop - 1; i > 0; i--) {
                let d = (speeds[i].s[6] - speeds[i - 1].s[6])
                // 速度差>0.4慢速
                if (d < Math.round(speeds[i - 1].s[6] * 0.4)) {
                    continue;
                }
                if (getRandomRange(1, d) > speeds[i - 1].s[6]) {
                    speeds.unshift(speeds[i]);
                }
            }
            // 不是深拷贝，又踩坑了
            // attackQueue = [...speeds];
            attackQueue = JSON.parse(JSON.stringify(speeds));
            console.log(attackQueue);
        }
        let timer = null;
        const deadFunc = (person) => {
            switch (person) {
                case 'h':
                    if (heroStat[0] <= 0) {
                        anim('h', 'dead');
                        console.log("玩家已死亡");
                        // 清除 battleScreen Map pet move faction 等 回到菜单界面
                        clearInterval(timer);
                        cleanData();
                        renderTips("你已阵亡,3s后返回主界面");
                        setTimeout(() => {
                            game.cleanAndEnterMenu();
                        }, 3000)
                    }
                    break;
                case 'm':
                    if (monsterStat[0] <= 0) {
                        console.log("怪物已死亡");
                        anim('m', 'dead');
                        updateMonsterStat()
                        updateHeroStat()
                        clearInterval(timer);
                        game.hero.heroInfo.hp = heroStat[0]
                        game.hero.heroInfo.mp = heroStat[1]
                        renderHeroStat();
                        // 
                        if (game.cur_map_floor == 3) {
                            console.log("你打败了最终BOSS");
                            renderTips("你打败了最终BOSS,3s后返回主界面");
                            setTimeout(() => {
                                game.cleanAndEnterMenu();
                            }, 3000)
                        }
                        // 奖励结算
                        if (game.hero.petInfo.readyPet.length + game.hero.petInfo.battlePet.length < 2) {
                            // 只能出战1只，备战1只
                            renderCatchScreen()
                        } else {
                            handleWin(false);
                        }
                    }
                    break;
                default:
                    if (typeof person == 'number' && typeof heroPetStat[person] == 'object' && heroPetStat[person][0] <= 0) {
                        console.log("宠物已死亡", person);
                        anim(person, 'dead');
                        updateHeroPetStat(person)
                        // 将宠物的行动移出 attackQueue
                        attackQueue = attackQueue.filter(e => e.tag != person);
                        attackQueue = attackQueue.map(e => {
                            if (e.t == person) {
                                e.t = 'h';
                            }
                        })
                        // 移出当前序列
                        heroPetStat.splice(person, 1);
                        // 宠物身上的 buff 也移除掉
                        petBuff.splice(person, 1);
                        game.hero.lostPetInBattle(person);
                    }
                    break;
            }
        }
        const calculateDamage = (tag, target) => {
            let _atk = null, _def = null, callback = [];
            switch (tag) {
                case 'h':
                    _atk = heroStat;
                    callback.push(updateHeroStat);
                    break;
                case 'm':
                    _atk = monsterStat
                    callback.push(updateMonsterStat)
                    break;
                default:
                    _atk = heroPetStat[tag]
                    callback.push(updateHeroPetStat)
                    break;
            }
            switch (target) {
                case 'h':
                    _def = heroStat;
                    callback.push(updateHeroStat);
                    break;
                case 'm':
                    _def = monsterStat;
                    callback.push(updateMonsterStat)
                    break;
                default:
                    _def = heroPetStat[target]
                    callback.push(updateHeroPetStat)
                    break;
            }
            if (!_atk || !_def) {
                console.log(_atk, _def, "伤害计算错误！");
                return;
            }
            const updateView = () => {
                if (_atk[0] > 0 && _def[0] > 0) {
                    // 更新攻击者和防御者的状态
                    for (let i = 0; i < 2; i++) {
                        if (callback[i] == updateHeroPetStat) {
                            callback[i](typeof target == 'number' ? target : tag);
                        } else {
                            callback[i]()
                        }
                    }
                    return;
                }
                if (_atk[0] <= 0) {
                    deadFunc(tag)
                }
                if (_def[0] <= 0) {
                    deadFunc(target)
                }
            }
            handleAllMove(tag, target);
            updateView();
            console.log(_atk, _def, "结算技能后")
            // 装载所有人的buff buff会在每次行动时消耗一层
            loadBuff(tag, target);
            // 行动之前，传入攻击方和被攻击方，只结算攻击方buff
            handleBattleQueue(tag, target);
            updateView()
            console.log(_atk, _def, "结算buff后")
            dealDamage(_atk, _def, tag, target)
            updateView()
            console.log(_atk, _def, "战斗伤害结算后")
        }
        timer = setInterval(() => {
            if (attackQueue.length == 0 && heroStat[0] > 0) {
                // 战时持续生效的物品生效一次，因为会生成buff，所以需要放在buff前面
                handleBattleHeroItem();
                addQueue()
            };
            let t = attackQueue.pop()
            if (t) {
                console.log(t.tag, "开始攻击", t.t)
                calculateDamage(t.tag, t.t)
            }
        }, turnTime);
    }
    const cleanData = () => {
        // 清除战斗时保存的数据
        battleQueue = [];
        heroBuff = [];
        petBuff = [];
        monsterBuff = [];
        // 退出战斗场景
        const bts = document.querySelector(".battleScreen")
        bts.style.display = "none";
        bts.firstElementChild.innerText = '';
        bts.lastElementChild.innerText = '';
    }
    const handleWin = (ifCatch) => {
        document.querySelector('.battleScreen .result').style.display = 'none';
        let _exp = Math.round(monsterData[mid].e + Math.max(0, heroStat[1] * 0.3));
        if (ifCatch) {
            game.hero.catchPet(mid);
            _exp = Math.round(_exp / 2);
        }
        game.hero.getExp(_exp);
        // 渲染英雄属性状态和血条等
        renderHeroStat();
        cleanData()
    }
    // 渲染获胜后可捕捉的画面
    const renderCatchScreen = () => {
        let _t = document.querySelector('.battleScreen .result');
        _t.style.display = 'block';
        let btns = _t.querySelectorAll('button');
        let ok = (e) => {
            handleWin(true);
        }
        let no = (e) => {
            handleWin(false);
        }
        if (btns.length == 0) {
            let btn1 = document.createElement('button'),
                btn2 = document.createElement('button');
            btn1.innerText = "尝试捕捉"
            // 按钮点不了
            btn2.innerText = "直接杀死"
            btn1.addEventListener('click', ok, { once: true })
            _t.append(btn1)
            btn2.addEventListener('click', no, { once: true })
            _t.append(btn2)
        } else {
            btns[0].addEventListener('click', ok, { once: true })
            btns[1].addEventListener('click', no, { once: true })
        }
    }
    battleResult()
}
